home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / charset.c < prev    next >
C/C++ Source or Header  |  1996-06-09  |  12KB  |  550 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. #include "vim.h"
  10. #include "globals.h"
  11. #include "proto.h"
  12. #include "option.h"
  13.  
  14. /*
  15.  * chartab[] is used
  16.  * - to quickly recognize ID characters
  17.  * - to quickly recognize file name characters
  18.  * - to store the size of a character on the screen: Printable is 1 position,
  19.  *     2 otherwise
  20.  */
  21. static char_u chartab[256];
  22. static int      chartab_initialized = FALSE;
  23.  
  24. #define CHAR_MASK        0x3        /* low two bits for size */
  25. #define CHAR_ID            0x4        /* third bit set for ID chars */
  26. #define CHAR_IF            0x8        /* fourth bit set for file name chars */
  27.  
  28. /*
  29.  * init_chartab(): Fill chartab[] with flags for ID and file name characters
  30.  * and the size of characters on the screen (1 or 2 positions).
  31.  * Also fills b_chartab[] with flags for keyword characters for current
  32.  * buffer.
  33.  *
  34.  * Return FAIL if 'iskeyword', 'isident', 'isfname' or 'isprint' option has an
  35.  * error, OK otherwise.
  36.  */
  37.     int
  38. init_chartab()
  39. {
  40.     int        c;
  41.     int        c2;
  42.     char_u    *p;
  43.     int        i;
  44.     int        tilde;
  45.     int        do_isalpha;
  46.  
  47.     /*
  48.      * Set the default size for printable characters:
  49.      * From <Space> to '~' is 1 (printable), others are 2 (not printable).
  50.      * This also inits all 'isident' and 'isfname' flags to FALSE.
  51.      */
  52.     c = 0;
  53.     while (c < ' ')
  54.         chartab[c++] = 2;
  55.     while (c <= '~')
  56.         chartab[c++] = 1;
  57.     while (c < 256)
  58.         chartab[c++] = 2;
  59.     
  60.     /*
  61.      * Init word char flags all to FALSE
  62.      */
  63.     if (curbuf != NULL)
  64.         for (c = 0; c < 256; ++c)
  65.             curbuf->b_chartab[c] = FALSE;
  66.  
  67.     /*
  68.      * In lisp mode the '-' character is included in keywords.
  69.      */
  70.     if (curbuf->b_p_lisp)
  71.         curbuf->b_chartab['-'] = TRUE;
  72.  
  73.     /* Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint'
  74.      * options Each option is a list of characters, character numbers or
  75.      * ranges, separated by commas, e.g.: "200-210,x,#-178,-"
  76.      */
  77.     for (i = 0; i < 4; ++i)
  78.     {
  79.         if (i == 0)
  80.             p = p_isi;                /* first round: 'isident' */
  81.         else if (i == 1)
  82.             p = p_isp;                /* second round: 'isprint' */
  83.         else if (i == 2)
  84.             p = p_isf;                /* third round: 'isfname' */
  85.         else    /* i == 3 */
  86.             p = curbuf->b_p_isk;    /* fourth round: 'iskeyword' */
  87.  
  88.         while (*p)
  89.         {
  90.             tilde = FALSE;
  91.             do_isalpha = FALSE;
  92.             if (*p == '^' && p[1] != NUL)
  93.             {
  94.                 tilde = TRUE;
  95.                 ++p;
  96.             }
  97.             if (isdigit(*p))
  98.                 c = getdigits(&p);
  99.             else
  100.                 c = *p++;
  101.             c2 = -1;
  102.             if (*p == '-' && p[1] != NUL)
  103.             {
  104.                 ++p;
  105.                 if (isdigit(*p))
  106.                     c2 = getdigits(&p);
  107.                 else
  108.                     c2 = *p++;
  109.             }
  110.             if (c < 0 || (c2 < c && c2 != -1) || c2 >= 256 ||
  111.                                                     !(*p == NUL || *p == ','))
  112.                 return FAIL;
  113.  
  114.             if (c2 == -1)        /* not a range */
  115.             {
  116.                 /*
  117.                  * A single '@' (not "@-@"):
  118.                  * Decide on letters being ID/printable/keyword chars with
  119.                  * standard function isalpha(). This takes care of locale.
  120.                  */
  121.                 if (c == '@')
  122.                 {
  123.                     do_isalpha = TRUE;
  124.                     c = 1;
  125.                     c2 = 255;
  126.                 }
  127.                 else
  128.                     c2 = c;
  129.             }
  130.             while (c <= c2)
  131.             {
  132.                 if (!do_isalpha || isalpha(c))
  133.                 {
  134.                     if (i == 0)                    /* (re)set ID flag */
  135.                     {
  136.                         if (tilde)
  137.                             chartab[c] &= ~CHAR_ID;
  138.                         else
  139.                             chartab[c] |= CHAR_ID;
  140.                     }
  141.                     else if (i == 1)            /* set printable to 1 or 2 */
  142.                     {
  143.                         if (c < ' ' || c > '~')
  144.                             chartab[c] = (chartab[c] & ~CHAR_MASK) +
  145.                                                               (tilde ? 2 : 1);
  146.                     }
  147.                     else if (i == 2)            /* (re)set fname flag */
  148.                     {
  149.                         if (tilde)
  150.                             chartab[c] &= ~CHAR_IF;
  151.                         else
  152.                             chartab[c] |= CHAR_IF;
  153.                     }
  154.                     else /* i == 3 */            /* (re)set keyword flag */
  155.                         curbuf->b_chartab[c] = !tilde;
  156.                 }
  157.                 ++c;
  158.             }
  159.             p = skip_to_option_part(p);
  160.         }
  161.     }
  162.     chartab_initialized = TRUE;
  163.     return OK;
  164. }
  165.  
  166. /*
  167.  * Translate any special characters in buf[bufsize].
  168.  * If there is not enough room, not all characters will be translated.
  169.  */
  170.     void
  171. trans_characters(buf, bufsize)
  172.     char_u    *buf;
  173.     int        bufsize;
  174. {
  175.     int        len;            /* length of string needing translation */
  176.     int        room;            /* room in buffer after string */
  177.     char_u    *new;            /* translated character */
  178.     int        new_len;        /* length of new[] */
  179.  
  180.     len = STRLEN(buf);
  181.     room = bufsize - len;
  182.     while (*buf)
  183.     {
  184.         new = transchar(*buf);
  185.         new_len = STRLEN(new);
  186.         if (new_len > 1)
  187.         {
  188.             room -= new_len - 1;
  189.             if (room <= 0)
  190.                 return;
  191.             vim_memmove(buf + new_len, buf + 1, (size_t)len);
  192.         }
  193.         vim_memmove(buf, new, (size_t)new_len);
  194.         buf += new_len;
  195.         --len;
  196.     }
  197. }
  198.  
  199. /*
  200.  * Catch 22: chartab[] can't be initialized before the options are
  201.  * initialized, and initializing options may cause transchar() to be called!
  202.  * When chartab_initialized == FALSE don't use chartab[].
  203.  */
  204.     char_u *
  205. transchar(c)
  206.     int     c;
  207. {
  208.     static char_u    buf[5];
  209.     int                i;
  210.  
  211.     i = 0;
  212.     if (IS_SPECIAL(c))        /* special key code, display as ~@ char */
  213.     {
  214.         buf[0] = '~';
  215.         buf[1] = '@';
  216.         i = 2;
  217.         c = K_SECOND(c);
  218.     }
  219.     if ((!chartab_initialized && c >= ' ' && c <= '~') ||
  220.                  (chartab[c] & CHAR_MASK) == 1)        /* printable character */
  221.     {
  222.         buf[i] = c;
  223.         buf[i + 1] = NUL;
  224.     }
  225.     else
  226.         transchar_nonprint(buf + i, c);
  227.     return buf;
  228. }
  229.  
  230.     void
  231. transchar_nonprint(buf, c)
  232.     char_u        *buf;
  233.     int            c;
  234. {
  235.     if (c <= 0x7f)                                    /* 0x00 - 0x1f and 0x7f */
  236.     {
  237.         if (c == NL)
  238.             c = NUL;                    /* we use newline in place of a NUL */
  239.         buf[0] = '^';
  240.         buf[1] = c ^ 0x40;                /* DEL displayed as ^? */
  241.         buf[2] = NUL;
  242.     }
  243.     else if (c >= ' ' + 0x80 && c <= '~' + 0x80)    /* 0xa0 - 0xfe */
  244.     {
  245.         buf[0] = '|';
  246.         buf[1] = c - 0x80;
  247.         buf[2] = NUL;
  248.     }
  249.     else                                            /* 0x80 - 0x9f and 0xff */
  250.     {
  251.         buf[0] = '~';
  252.         buf[1] = (c - 0x80) ^ 0x40;        /* 0xff displayed as ~? */
  253.         buf[2] = NUL;
  254.     }
  255. }
  256.  
  257. /*
  258.  * return the number of characters 'c' will take on the screen
  259.  * This is used very often, keep it fast!!!
  260.  */
  261.     int
  262. charsize(c)
  263.     register int c;
  264. {
  265.     if (IS_SPECIAL(c))
  266.         return (chartab[K_SECOND(c)] & CHAR_MASK) + 2;
  267.     return (chartab[c] & CHAR_MASK);
  268. }
  269.  
  270. /*
  271.  * Return the number of characters string 's' will take on the screen, 
  272.  * counting TABs as two characters: "^I".
  273.  */
  274.     int
  275. strsize(s)
  276.     register char_u *s;
  277. {
  278.     register int    len = 0;
  279.  
  280.     while (*s)
  281.         len += charsize(*s++);
  282.     return len;
  283. }
  284.  
  285. /*
  286.  * Return the number of characters 'c' will take on the screen, taking
  287.  * into account the size of a tab.
  288.  * Use a define to make it fast, this is used very often!!!
  289.  * Also see getvcol() below.
  290.  */
  291.  
  292. #define RET_WIN_BUF_CHARTABSIZE(wp, buf, c, col) \
  293.        if ((c) == TAB && !(wp)->w_p_list) \
  294.     { \
  295.         register int ts; \
  296.         ts = (buf)->b_p_ts; \
  297.            return (int)(ts - (col % ts)); \
  298.     } \
  299.        else \
  300.         return charsize(c);
  301.  
  302.     int
  303. chartabsize(c, col)
  304.     register int    c;
  305.     colnr_t            col;
  306. {
  307.     RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, c, col)
  308. }
  309.  
  310.     int
  311. win_chartabsize(wp, c, col)
  312.     register WIN    *wp;
  313.     register int    c;
  314.     colnr_t            col;
  315. {
  316.     RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, c, col)
  317. }
  318.  
  319. /*
  320.  * return the number of characters the string 's' will take on the screen,
  321.  * taking into account the size of a tab
  322.  */
  323.     int
  324. linetabsize(s)
  325.     char_u        *s;
  326. {
  327.     colnr_t    col = 0;
  328.  
  329.     while (*s != NUL)
  330.         col += lbr_chartabsize(s++, col);
  331.     return (int)col;
  332. }
  333.  
  334. /*
  335.  * return TRUE if 'c' is a normal identifier character
  336.  * letters and characters from 'isident' option.
  337.  */
  338.     int
  339. isidchar(c)
  340.     int c;
  341. {
  342.     return (c < 0x100 && (chartab[c] & CHAR_ID));
  343. }
  344.  
  345. /*
  346.  * return TRUE if 'c' is a keyword character: Letters and characters from
  347.  * 'iskeyword' option for current buffer.
  348.  */
  349.     int
  350. iswordchar(c)
  351.     int c;
  352. {
  353.     return (c < 0x100 && curbuf->b_chartab[c]);
  354. }
  355.  
  356. /*
  357.  * return TRUE if 'c' is a valid file-name character
  358.  */
  359.     int
  360. isfilechar(c)
  361.     int    c;
  362. {
  363.     return (c < 0x100 && (chartab[c] & CHAR_IF));
  364. }
  365.  
  366. /*
  367.  * return TRUE if 'c' is a printable character
  368.  */
  369.     int
  370. isprintchar(c)
  371.     int c;
  372. {
  373.     return (c < 0x100 && (chartab[c] & CHAR_MASK) == 1);
  374. }
  375.  
  376. /*
  377.  * like chartabsize(), but also check for line breaks on the screen
  378.  */
  379.     int
  380. lbr_chartabsize(s, col)
  381.     unsigned char    *s;
  382.     colnr_t            col;
  383. {
  384.     if (!curwin->w_p_lbr && *p_sbr == NUL)
  385.         RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, *s, col)
  386.  
  387.     return win_lbr_chartabsize(curwin, s, col, NULL);
  388. }
  389.  
  390. /*
  391.  * This function is used very often, keep it fast!!!!
  392.  * Warning: *head is only set if it's a non-zero value, init to 0 before
  393.  * calling.
  394.  */
  395.     int
  396. win_lbr_chartabsize(wp, s, col, head)
  397.     WIN                *wp;
  398.     unsigned char    *s;
  399.     colnr_t            col;
  400.     int                *head;
  401. {
  402.     int        c = *s;
  403.     int        size;
  404.     colnr_t    col2;
  405.     colnr_t    colmax;
  406.     int        added;
  407.     int     numberextra;
  408.  
  409. /*
  410.  * No 'linebreak' and 'showbreak': return quickly.
  411.  */
  412.     if (!wp->w_p_lbr && *p_sbr == NUL)
  413.         RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, c, col)
  414.  
  415. /*
  416.  * First get normal size, without 'linebreak'
  417.  */
  418.     size = win_chartabsize(wp, c, col);
  419. /*
  420.  * If 'linebreak' set check at a blank before a non-blank if the line needs a
  421.  * break here
  422.  */
  423.     if (wp->w_p_lbr && isbreak(c) && !isbreak(s[1]) &&
  424.                                                !wp->w_p_list && wp->w_p_wrap)
  425.     {
  426.         numberextra = curwin->w_p_nu? 8: 0;
  427.         /* count all characters from first non-blank after a blank up to next
  428.          * non-blank after a blank */
  429.         col2 = col;
  430.         colmax = (((col + numberextra) / Columns) + 1) * Columns;
  431.         while ((c = *++s) != NUL && (isbreak(c) ||
  432.                             (!isbreak(c) && (col2 == col || !isbreak(s[-1])))))
  433.         {
  434.             col2 += win_chartabsize(wp, c, col2);
  435.             if (col2 + numberextra >= colmax)            /* doesn't fit */
  436.             {
  437.                 size = Columns - ((col + numberextra) % Columns);
  438.                 break;
  439.             }
  440.         }
  441.     }
  442.     
  443. /*
  444.  * May have to add something for 'showbreak' string at start of line
  445.  * Set *head to the size of what we add.
  446.  */
  447.     added = 0;
  448.     if (*p_sbr != NUL && wp->w_p_wrap && col)
  449.     {
  450.         numberextra = curwin->w_p_nu? 8: 0;
  451.         col = (col + numberextra) % Columns;
  452.         if (col == 0 || col + size > (colnr_t)Columns)
  453.         {
  454.             added = STRLEN(p_sbr);
  455.             size += added;
  456.             if (col != 0)
  457.                 added = 0;
  458.         }
  459.     }
  460.     if (head != NULL)
  461.         *head = added;
  462.     return size;
  463. }
  464.  
  465. /*
  466.  * get virtual column number of pos
  467.  * start: on the first position of this character (TAB, ctrl)
  468.  * cursor: where the cursor is on this character (first char, except for TAB)
  469.  * end: on the last position of this character (TAB, ctrl)
  470.  */
  471.     void
  472. getvcol(wp, pos, start, cursor, end)
  473.     WIN            *wp;
  474.     FPOS        *pos;
  475.     colnr_t        *start;
  476.     colnr_t        *cursor;
  477.     colnr_t        *end;
  478. {
  479.     int                col;
  480.     colnr_t            vcol;
  481.     char_u           *ptr;
  482.     int             incr;
  483.     int                head;
  484.     int                ts = wp->w_buffer->b_p_ts;
  485.     int                c;
  486.  
  487.     vcol = 0;
  488.     ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
  489.  
  490.     /*
  491.      * This function is used very often, do some speed optimizations.
  492.      * When 'list', 'linebreak' and 'showbreak' are not set use a simple loop.
  493.      */
  494.     if (!wp->w_p_list && !wp->w_p_lbr && *p_sbr == NUL)
  495.     {
  496.         head = 0;
  497.         for (col = pos->col; ; --col, ++ptr)
  498.         {
  499.             c = *ptr;
  500.                     /* make sure we don't go past the end of the line */
  501.             if (c == NUL)
  502.             {
  503.                 incr = 1;        /* NUL at end of line only takes one column */
  504.                 break;
  505.             }
  506.                     /* A tab gets expanded, depending on the current column */
  507.             if (c == TAB)
  508.                 incr = ts - (vcol % ts);
  509.             else
  510.                 incr = charsize(c);
  511.  
  512.             if (col == 0)        /* character at pos.col */
  513.                 break;
  514.  
  515.             vcol += incr;
  516.         }
  517.     }
  518.     else
  519.     {
  520.         for (col = pos->col; ; --col, ++ptr)
  521.         {
  522.                     /* A tab gets expanded, depending on the current column */
  523.             head = 0;
  524.             incr = win_lbr_chartabsize(wp, ptr, vcol, &head);
  525.                     /* make sure we don't go past the end of the line */
  526.             if (*ptr == NUL)
  527.             {
  528.                 incr = 1;        /* NUL at end of line only takes one column */
  529.                 break;
  530.             }
  531.  
  532.             if (col == 0)        /* character at pos.col */
  533.                 break;
  534.  
  535.             vcol += incr;
  536.         }
  537.     }
  538.     if (start != NULL)
  539.         *start = vcol + head;
  540.     if (end != NULL)
  541.         *end = vcol + incr - 1;
  542.     if (cursor != NULL)
  543.     {
  544.         if (*ptr == TAB && (State & NORMAL) && !wp->w_p_list)
  545.             *cursor = vcol + incr - 1;        /* cursor at end */
  546.         else
  547.             *cursor = vcol + head;            /* cursor at start */
  548.     }
  549. }
  550.